﻿using System;
using System.Deployment.Application;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;

namespace MidnightPeach.Engine.Components
{
    public class LocalStorage
    {
        private static string _storageDirectory;

        public static string StorageDirectory
        {
            get
            {
                if (_storageDirectory == null)
                    _storageDirectory = (ApplicationDeployment.IsNetworkDeployed) ? ApplicationDeployment.CurrentDeployment.DataDirectory + "\\" : Environment.CurrentDirectory + "\\";

                return _storageDirectory;
            }
        }

        public static string GetPath(string fileName)
        {
            return StorageDirectory + fileName;
        }

        public static void WriteAllText(string fileName, string contents)
        {
            File.WriteAllText(StorageDirectory + fileName, contents);
        }

        public static string ReadAllText(string fileName)
        {
            return File.ReadAllText(StorageDirectory + fileName);
        }

        public static void WriteAllBytesInIsoratedStorage(string fileName, byte[] bytes)
        {
            File.WriteAllBytes(StorageDirectory + fileName, bytes);
        }

        public static byte[] ReadAllBytesInIsoratedStorage(string fileName)
        {
            return File.ReadAllBytes(StorageDirectory + fileName);
        }

        public static void WriteAllBytes(string filePath, byte[] bytes)
        {
            File.WriteAllBytes(filePath, bytes);
        }

        public static byte[] ReadAllBytes(string filePath)
        {
            return File.ReadAllBytes(filePath);
        }

        public static bool Exists(string fileName)
        {
            return File.Exists(StorageDirectory + fileName);
        }

        public static void DeleteAllFiles(string searchPattern, params string[] exceptions)
        {
            var files = Directory.GetFiles(StorageDirectory, searchPattern);

            foreach (var file in files)
            {
                if (Array.IndexOf(exceptions, file) >= 0)
                    continue;

                try
                {
                    File.Delete(file);
                }
                catch
                {
                }
            }
        }

        public static byte[] SerializeToBytes<T>(T @object, bool withCompression) where T : class
        {
            MemoryStream stream = new MemoryStream();

            DataContractSerializer serializer = new DataContractSerializer(typeof (T));
            serializer.WriteObject(stream, @object);

            var bytes = stream.ToArray();
            stream.Close();

            if (withCompression)
                bytes = Compress(bytes);

            return bytes;
        }

        public static void SerializeToFile<T>(string fileName, T @object) where T : class
        {
            var bytes = SerializeToBytes(@object, false);
            WriteAllBytes(fileName, bytes);
        }

        public static T DeserializeFromBytes<T>(byte[] bytes, bool withCompression) where T : class
        {
            if (withCompression)
                bytes = Decompress(bytes);

            MemoryStream stream = new MemoryStream(bytes);

            DataContractSerializer serializer = new DataContractSerializer(typeof (T));
            var @object = (T) serializer.ReadObject(stream);

            stream.Close();

            return @object;
        }

        public static void DeserializeFromFile<T>(string fileName, out T @object) where T : class
        {
            var bytes = ReadAllBytes(fileName);
            @object = DeserializeFromBytes<T>(bytes, false);
        }

        private static byte[] Compress(byte[] bytes)
        {
            MemoryStream ms = new MemoryStream();
            DeflateStream ds = new DeflateStream(ms, CompressionMode.Compress);

            ds.Write(bytes, 0, bytes.Length);
            ds.Close();

            return ms.ToArray();
        }

        private static byte[] Decompress(byte[] bytes)
        {
            MemoryStream ms = new MemoryStream(bytes);
            DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);

            byte[] buffer = new byte[bytes.Length * 20];
            int count = ds.Read(buffer, 0, buffer.Length);
            ds.Close();

            byte[] result = new byte[count];
            Array.Copy(buffer, result, count);
            return result;
        }

        public static void WriteObject<T>(string filePath, T @object) where T : new()
        {
            FileStream writer = new FileStream(filePath, FileMode.Create);
            DataContractSerializer serializer = new DataContractSerializer(typeof (T));

            serializer.WriteObject(writer, @object);
            writer.Close();
        }

        public static T ReadObject<T>(string filePath)
        {
            FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            var quotas = new XmlDictionaryReaderQuotas();
            quotas.MaxStringContentLength = int.MaxValue;
            XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, quotas);
            DataContractSerializer serializer = new DataContractSerializer(typeof (T));

            T @object = (T) serializer.ReadObject(reader, true);
            reader.Close();
            stream.Close();

            return @object;
        }
    }
}